package com.wechat.service.impl;

import com.wechat.entity.constants.Constants;
import com.wechat.entity.dto.MessageSendDto;
import com.wechat.entity.dto.TokenUserInfoDto;
import com.wechat.entity.enums.*;
import com.wechat.entity.po.GroupInfo;
import com.wechat.entity.po.UserContact;
import com.wechat.entity.po.UserContactApply;
import com.wechat.entity.po.UserInfo;
import com.wechat.entity.query.*;
import com.wechat.entity.vo.PaginationResultVO;
import com.wechat.exception.BusinessException;
import com.wechat.mappers.GroupInfoMapper;
import com.wechat.mappers.UserContactApplyMapper;
import com.wechat.mappers.UserContactMapper;
import com.wechat.mappers.UserInfoMapper;
import com.wechat.service.UserContactApplyService;
import com.wechat.service.UserContactService;
import com.wechat.utils.StringTools;
import com.wechat.websocket.MessageHandler;
import jodd.util.ArraysUtil;
import org.apache.commons.lang3.ArrayUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;


/**
 * 联系人申请 业务接口实现
 */
@Service("userContactApplyService")
public class UserContactApplyServiceImpl implements UserContactApplyService {

    @Resource
    private UserContactApplyMapper<UserContactApply, UserContactApplyQuery> userContactApplyMapper;

    @Resource
    private UserContactMapper<UserContact, UserContactQuery> userContactMapper;

    @Resource
    private GroupInfoMapper<GroupInfo, GroupInfoQuery> groupInfoMapper;

    @Resource
    private UserInfoMapper<UserInfo, UserInfoQuery> userInfoMapper;

    @Resource
    private MessageHandler messageHandler;

    @Resource
    private UserContactService userContactService;

    /**
     * 根据条件查询列表
     */
    @Override
    public List<UserContactApply> findListByParam(UserContactApplyQuery param) {
        return this.userContactApplyMapper.selectList(param);
    }

    /**
     * 根据条件查询列表
     */
    @Override
    public Integer findCountByParam(UserContactApplyQuery param) {
        return this.userContactApplyMapper.selectCount(param);
    }

    /**
     * 分页查询方法
     */
    @Override
    public PaginationResultVO<UserContactApply> findListByPage(UserContactApplyQuery param) {
        int count = this.findCountByParam(param);//查询总数
        int pageSize = param.getPageSize() == null ? PageSize.SIZE15.getSize() : param.getPageSize();

        SimplePage page = new SimplePage(param.getPageNo(), count, pageSize);
        param.setSimplePage(page);
        List<UserContactApply> list = this.findListByParam(param);//查询列表
        PaginationResultVO<UserContactApply> result = new PaginationResultVO(count, page.getPageSize(), page.getPageNo(), page.getPageTotal(), list);
        return result;
    }

    /**
     * 新增
     */
    @Override
    public Integer add(UserContactApply bean) {
        return this.userContactApplyMapper.insert(bean);
    }

    /**
     * 批量新增
     */
    @Override
    public Integer addBatch(List<UserContactApply> listBean) {
        if (listBean == null || listBean.isEmpty()) {
            return 0;
        }
        return this.userContactApplyMapper.insertBatch(listBean);
    }

    /**
     * 批量新增或者修改
     */
    @Override
    public Integer addOrUpdateBatch(List<UserContactApply> listBean) {
        if (listBean == null || listBean.isEmpty()) {
            return 0;
        }
        return this.userContactApplyMapper.insertOrUpdateBatch(listBean);
    }

    /**
     * 多条件更新
     */
    @Override
    public Integer updateByParam(UserContactApply bean, UserContactApplyQuery param) {
        StringTools.checkParam(param);
        return this.userContactApplyMapper.updateByParam(bean, param);
    }

    /**
     * 多条件删除
     */
    @Override
    public Integer deleteByParam(UserContactApplyQuery param) {
        StringTools.checkParam(param);
        return this.userContactApplyMapper.deleteByParam(param);
    }

    /**
     * 根据ApplyId获取对象
     */
    @Override
    public UserContactApply getUserContactApplyByApplyId(Integer applyId) {
        return this.userContactApplyMapper.selectByApplyId(applyId);
    }

    /**
     * 根据ApplyId修改
     */
    @Override
    public Integer updateUserContactApplyByApplyId(UserContactApply bean, Integer applyId) {
        return this.userContactApplyMapper.updateByApplyId(bean, applyId);
    }

    /**
     * 根据ApplyId删除
     */
    @Override
    public Integer deleteUserContactApplyByApplyId(Integer applyId) {
        return this.userContactApplyMapper.deleteByApplyId(applyId);
    }

    /**
     * 根据ApplyUserIdAndReceiveUserIdAndContactId获取对象
     */
    @Override
    public UserContactApply getUserContactApplyByApplyUserIdAndReceiveUserIdAndContactId(String applyUserId, String receiveUserId, String contactId) {
        return this.userContactApplyMapper.selectByApplyUserIdAndReceiveUserIdAndContactId(applyUserId, receiveUserId, contactId);
    }

    /**
     * 根据ApplyUserIdAndReceiveUserIdAndContactId修改
     */
    @Override
    public Integer updateUserContactApplyByApplyUserIdAndReceiveUserIdAndContactId(UserContactApply bean, String applyUserId, String receiveUserId, String contactId) {
        return this.userContactApplyMapper.updateByApplyUserIdAndReceiveUserIdAndContactId(bean, applyUserId, receiveUserId, contactId);
    }

    /**
     * 根据ApplyUserIdAndReceiveUserIdAndContactId删除
     */
    @Override
    public Integer deleteUserContactApplyByApplyUserIdAndReceiveUserIdAndContactId(String applyUserId, String receiveUserId, String contactId) {
        return this.userContactApplyMapper.deleteByApplyUserIdAndReceiveUserIdAndContactId(applyUserId, receiveUserId, contactId);
    }


    /**
     * 申请添加联系人
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer applyAdd(TokenUserInfoDto tokenUserInfoDto, String contactId,  String applyInfo) {
       UserContactTypeEnum typeEnum = UserContactTypeEnum.getByPrefix(contactId);
       if (null == typeEnum) {
           throw new BusinessException(ResponseCodeEnum.CODE_600);
       }
       //获取申请人id
        String applyUserId = tokenUserInfoDto.getUserId();
        //设置默认申请信息
        applyInfo =StringTools.isEmpty(applyInfo) ? String.format(Constants.APPLY_INFO_TEMPLATE, tokenUserInfoDto.getNickName()):applyInfo;

        Long curTime = System.currentTimeMillis();

        Integer joinType = null;
        String receiveUserId = contactId;

        //查询是否是好友但被拉黑----拉黑后无法添加
        UserContact userContact = userContactService.getUserContactByUserIdAndContactId(applyUserId, contactId);
        if(userContact != null &&
                ArraysUtil.contains(new Integer[]{
                        UserContactStatusEnum.BLACKLIST_BE.getStatus(),
                        UserContactStatusEnum.BLACKLIST_BE_FIRST.getStatus()
                }, userContact.getStatus()))
        {
            throw new BusinessException("已被对方拉黑，无法添加");
        }

        //类型是群聊
        if(typeEnum == UserContactTypeEnum.GROUP){
            GroupInfo groupInfo = groupInfoMapper.selectByGroupId(contactId);
            if(groupInfo == null || GroupStatusEnum.DISSOLUTION.getStatus().equals(groupInfo.getStatus())){
                throw new BusinessException("群聊不存在或已解散");
            }
            receiveUserId=groupInfo.getGroupOwnerId();
            joinType = groupInfo.getJoinType();
        }

        //类型是好友
        if(typeEnum == UserContactTypeEnum.USER){
            UserInfo userInfo = userInfoMapper.selectByUserId(contactId);
            if(userInfo == null){
                throw new BusinessException("用户不存在");
            }
            joinType = userInfo.getJoinType();
        }

        //如果加入类型是直接加入，不需要申请记录
        if(JoinTypeEnum.JOIN.getType().equals(joinType)){
            userContactService.addContact(applyUserId, receiveUserId, contactId, typeEnum.getType(), applyInfo);

            return joinType;
        }
        //加入类型需要审核，添加申请记录
        //如果已经存在申请记录，则更新申请记录；否则添加申请记录
        UserContactApply dbApply = userContactApplyMapper.selectByApplyUserIdAndReceiveUserIdAndContactId(applyUserId, receiveUserId, contactId);//查询申请记录
        if(dbApply == null){
            //添加申请记录
            UserContactApply applyRecord = UserContactApply.builder()
                    .applyUserId(applyUserId)
                    .receiveUserId(receiveUserId)
                    .contactId(contactId)
                    .contactType(typeEnum.getType())
                    .status(UserContactApplyStatusEnum.INIT.getStatus())
                    .applyInfo(applyInfo)
                    .lastApplyTime(curTime)
                    .build();
            userContactApplyMapper.insert(applyRecord);
        }else{
            //更新申请记录
            UserContactApply applyUpdate = UserContactApply.builder()
                    .status(UserContactApplyStatusEnum.INIT.getStatus())
                    .lastApplyTime(curTime)
                    .build();
            userContactApplyMapper.updateByApplyId(applyUpdate, dbApply.getApplyId());
        }
        //避免重复发送通知消息：第一次申请发送通知
        //当用户重复点击"申请添加好友"时：
// 情况1：dbApply != null 且状态为 INIT（待处理）
// 这说明申请已经在等待处理中，不需要重复发送通知

// 情况2：dbApply != null 但状态不是 INIT（已被拒绝/通过等）
// 这说明之前的申请已经处理完毕，现在是新的申请，需要发送通知

        if(dbApply == null || UserContactApplyStatusEnum.INIT.getStatus() != dbApply.getStatus()){
            //发送ws消息给用户
            MessageSendDto sendDto = MessageSendDto.builder()
                    .messageType(MessageTypeEnum.CONTACT_APPLY.getType())
                    .messageContent(applyInfo)
                    .contactId(receiveUserId)
                    .build();
            messageHandler.sendMessage(sendDto);//发送信息

        }
        return joinType;

    }

    /**
     * 处理申请：拒绝/通过/拉黑
     * @param userId---处理人id
     * @param applyId---申请表的唯一id
     * @param status---处理的状态
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void dealWithApply(String userId, Integer applyId, Integer status) {
        //获取处理状态
        UserContactApplyStatusEnum statusEnum = UserContactApplyStatusEnum.getByStatus(status);
        if(statusEnum == null || statusEnum.equals(UserContactApplyStatusEnum.INIT.getStatus())){
            throw new BusinessException("处理状态错误");
        }
        //判断处理人是否与申请人所申请人一致
        UserContactApply applyInfo = userContactApplyMapper.selectByApplyId(applyId);
        if(applyInfo == null || !userId.equals(applyInfo.getApplyUserId())){
            //throw new BusinessException("处理人错误");
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }
        //修改申请状态
        UserContactApply applyUpdate = UserContactApply.builder()
                .status(statusEnum.getStatus())
                .lastApplyTime(System.currentTimeMillis())
                .build();
        //设置查询条件---数据库中的状态为待处理
        UserContactApplyQuery applyQuery = UserContactApplyQuery.builder()
                .applyId(applyId)
                .status(UserContactApplyStatusEnum.INIT.getStatus())//设置乐观锁条件：待处理状态
                .build();

        //乐观锁,避免并发修改(仅支持从待处理状态——>处理状态，不可以已处理——>已处理)
        //sql: update user_contact_apply set status = #{status},last_apply_time = #{lastApplyTime} where apply_id = #{applyId} and status = 0
        Integer count = userContactApplyMapper.updateByParam(applyUpdate, applyQuery);
        if(count == 0){//count是受操作影响的行数，如果为0，则说明该申请已被处理
            throw new BusinessException(ResponseCodeEnum.CODE_600);
        }

        //处理同意状态
        if(statusEnum.equals(UserContactApplyStatusEnum.PASS.getStatus())){
            userContactService.addContact(applyInfo.getApplyUserId(), applyInfo.getReceiveUserId(), applyInfo.getContactId(), applyInfo.getContactType(), applyInfo.getApplyInfo());
        }

        //处理拒绝状态
        if(statusEnum.equals(UserContactApplyStatusEnum.REJECT.getStatus())){
            //不需要进行处理
        }

        //处理拉黑状态---被拉黑,需要记录该联系人进入我的联系人表中，设置为拉黑状态
        if(statusEnum.equals(UserContactApplyStatusEnum.BLACKLIST.getStatus())){
            //更新联系人状态---拉黑的人存在联系人表中，则更新状态为拉黑;被拉黑的联系人不存在好友列表中（即添加时处理为拉黑），则添加入联系人表并设置状态为拉黑用于添加好友时判断
             Date date = new Date();
             //将被拉黑者（申请人）添加到处理者的通讯录中
             UserContact userContact = UserContact.builder()
                     .userId(applyInfo.getApplyUserId())
                     .contactId(applyInfo.getContactId())
                     .status(UserContactStatusEnum.BLACKLIST_BE_FIRST.getStatus())
                     .contactType(applyInfo.getContactType())
                     .createTime(date)
                     .lastUpdateTime(date)
                     .build();
             userContactMapper.insertOrUpdate(userContact);


        }



    }

}